package com.simen.invoker;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by zhangming on 16/8/1.
 */
public final class Invoker {

    /**
     * 获取类对象
     */
    public static Object newInstance(String className) throws ClassNotFoundException,
            IllegalAccessException, InstantiationException {
        Class<?> classType = Class.forName(className);
        return classType.newInstance();
    }

    /**
     * 获取类对象
     */
    public static Object newInstance(String className, boolean shouldInitialize, ClassLoader
            classLoader) throws ClassNotFoundException, IllegalAccessException,
            InstantiationException {
        Class<?> classType = Class.forName(className, shouldInitialize, classLoader);
        return classType.newInstance();
    }

    /**
     * 根据构造参数获取类对象
     */
    public static <T> T newInstance(Class<?> classType, Class<?>[] parameterTypes, Object...
            args) throws
            NoSuchMethodException, IllegalAccessException, InvocationTargetException,
            InstantiationException {
        Constructor<T> constructor = (Constructor<T>) classType.getDeclaredConstructor
                (parameterTypes);
        if (!constructor.isAccessible()) {
            constructor.setAccessible(true);
        }
        return constructor.newInstance(args);
    }

    /**
     * 修改对象的变量值
     *
     * @param object    对象
     * @param fieldName 变量名
     * @param value     目标值
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void invokeValue(Object object, String fieldName, Object value) throws
            NoSuchFieldException, IllegalAccessException {
        Field field = object.getClass().getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        field.set(object, value);
    }

    public static Object getValue(Object object, String fieldName) throws NoSuchFieldException,
            IllegalAccessException {
        Field field = object.getClass().getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        return field.get(object);
    }

    /**
     * 获取对象的父类成员值
     * 例子:
     * Object value=getValue(Base.class, grand, "name");
     *
     * @param classType object对象的父类
     * @param object    对象
     * @param fieldName 成员名
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Object getValue(Class<?> classType, Object object, String fieldName) throws
            NoSuchFieldException, IllegalAccessException {
        Field field = classType.getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        return field.get(object);
    }

    /**
     * 设置对象的父类成员值
     * 例子:
     * invokeValue(Base.class, grand, "name", "new value");
     *
     * @param classType object对象的父类
     * @param object    对象
     * @param fieldName 成员名
     * @param value     值
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    public static void invokeValue(Class<?> classType, Object object, String fieldName, Object
            value) throws IllegalAccessException, NoSuchFieldException {
        Field field = classType.getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        field.set(object, value);
    }

    /**
     * 修改类的静态变量值
     *
     * @param classType 类
     * @param fieldName 变量名
     * @param value     目标值
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void invokeStaticValue(Class classType, String fieldName, Object value) throws
            NoSuchFieldException, IllegalAccessException {
        Field field = classType.getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        field.set(null, value);
    }

    public static Object getStaticValue(Class classType, String fieldName) throws
            NoSuchFieldException, IllegalAccessException {
        Field field = classType.getDeclaredField(fieldName);
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        return field.get(null);
    }

    /**
     * 调用对象的内部方法(private,proteced,public)
     *
     * @param object         对象
     * @param methodName     方法名
     * @param parameterTypes 方法参数类型数组
     * @param args           参数值
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object invokeMethod(Object object, String methodName, Class<?>[]
            parameterTypes, Object... args) throws
            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = object.getClass().getDeclaredMethod(methodName, parameterTypes);
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        return method.invoke(object, args);
    }

    /**
     * 调用类的内部方法(private,proteced,public)
     *
     * @param classType      类
     * @param methodName     方法名
     * @param parameterTypes 方法参数类型数组
     * @param args           参数值
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object invokeStaticMethod(Class classType, String methodName, Class<?>[]
            parameterTypes, Object... args) throws
            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = classType.getDeclaredMethod(methodName, parameterTypes);
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        return method.invoke(null, args);
    }

    /**
     * 调用对象父类的内部方法(private,proteced,public)
     * 例子:
     * invokeMethod(PackageClass.class, grand, "getValue", new Class[]{String.class}, "extension");
     *
     * @param classType      对象父类
     * @param object         对象
     * @param methodName     方法名
     * @param parameterTypes 方法参数类型数组
     * @param args           参数值
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object invokeMethod(Class<?> classType, Object object, String methodName,
                                      Class<?>[] parameterTypes, Object... args) throws
            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = classType.getDeclaredMethod(methodName, parameterTypes);
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        return method.invoke(object, args);
    }
}
